package com._5704.website.controller;


import com._5704.website.entity.Code;
import com._5704.website.util.CodeUtil;
import com._5704.website.entity.ToEmail;
import com._5704.website.entity.User;
import com._5704.website.exception.WebsiteException;
import com._5704.website.exception.WebsiteExceptionEnum;
import com._5704.website.form.LoginForm;
import com._5704.website.form.PwdForm;
import com._5704.website.form.UserForm;
import com._5704.website.form.RegisterForm;
import com._5704.website.service.ServiceImpl.UserServiceImpl;
import com._5704.website.shiro.JwtToken;
import com._5704.website.util.*;
import com._5704.website.vo.JsonVO;
import com._5704.website.vo.userVO.UserVO;
import lombok.extern.log4j.Log4j2;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import javax.validation.constraints.Email;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.Size;
import java.util.*;

/**
 * <p>
 *  前端控制器
 * </p>
 *
 * @author Yiyoung
 * @since 2021-07-25
 */
@RestController
@RequestMapping("/user")
@Validated
@Log4j2
public class UserController {
    @Autowired
    private UserServiceImpl userService;
//    @Autowired
//    private EmailUtil emailUtil;

    /**
     * 登录
     * @param loginForm 登录表单
     * @param bindingResult 数据绑定
     * @return Json
     */
    @PostMapping("/login")
    public JsonVO<Object> login(@Valid @RequestBody LoginForm loginForm , BindingResult bindingResult){
        String userId = loginForm.getId();
        RedisUtil.delete("userInfo:"+userId);
        User user = userService.getUser(userId);
        if (user.getPerms() == -1){
            throw new WebsiteException(WebsiteExceptionEnum.USER_IS_IN_BLACKLIST);
        }
        // 验证用户并获得盐
        String salt = user.getSalt();

        // 将登录的密码进行加盐加密
        String loginPwd = userService.encryptionPwd(loginForm.getPwd(),salt);

        // 验证密码
        userService.verifyPwd(loginPwd,user.getPwd());

        // 设置登陆时间
        user.setLastLoginTime(new Date());
        userService.updateUser(user);

        // 设置Token
        JwtToken jwtToken = userService.setToken(userId);

        return JsonUtil.success(jwtToken);
    }

    /**
     * 注册
     * @param registerForm 注册表单
     * @param bindingResult 数据绑定
     * @return
     */
    @Transactional
    @PostMapping("/register")

    public JsonVO<Object> register(@Valid @RequestBody RegisterForm registerForm,BindingResult bindingResult,HttpServletRequest request){
        // 检查邀请码码
        if(!registerForm.getInviteCode().equals("cdut5704")){
            throw new WebsiteException(WebsiteExceptionEnum.INYITE_CODE_ERROR);
        }

        // 检查验证码
        String userId = registerForm.getId();

        String code = RedisUtil.getValue(userId+"注册账号");
        if (code == null || !code.equals(registerForm.getCode())){
            throw new WebsiteException(WebsiteExceptionEnum.CODE_ERROR);
        }
        // 检查用户是否存在
        User user = null;
        // 用户为空则捕获异常
        try{
            user = userService.getUser(registerForm.getId());
        } catch (WebsiteException ignored){}
        // 用户不为空则抛出异常
        if (user != null){
            throw new WebsiteException(WebsiteExceptionEnum.USER_HAS_REGISTERED);
        }

        // 设置盐u
        String salt = GetRandomUtil.getRandomString(4);
        // 密码加密
        String pwd =  userService.encryptionPwd(registerForm.getPwd(), salt);
        // 设置用户
        user = new User()
                .setUserId(registerForm.getId())
                .setPwd(pwd)
                .setSalt(salt)
                .setAvatar("avatar/0.png")
                .setCreateTime(new Date())
                .setName("用户"+registerForm.getId());
        // 插入用户
        userService.insertUser(user);

        return login(new LoginForm(registerForm.getId(), registerForm.getPwd()), bindingResult);
    }

    /**
     * 修改个人信息
     * @param userForm 信息表
     * @param token token
     * @return
     */
    @RequiresRoles("user")
    @PostMapping("/modify")
    public JsonVO<String> modify(@RequestBody UserForm userForm, @RequestHeader("token")String token){

        // 得到用户
        User user = userService.getUser(JwtUtil.getUserId(token));
        // 设置更新信息
        userService.setModifyData(user, userForm);
        // 更新用户
        userService.updateUser(user);

        return JsonUtil.success();
    }

//    @RequiresRoles("user")
    @PostMapping("/modifyPwd")
    public JsonVO<String> modifyPwd(@Valid @RequestBody PwdForm pwdForm){
//        String userId = JwtUtil.getUserId(token);

        // 检查验证码
        String userId = pwdForm.getId();

        String code = RedisUtil.getValue(userId+"修改密码");
        if (code == null || !code.equals(pwdForm.getCode())){
            throw new WebsiteException(WebsiteExceptionEnum.CODE_ERROR);
        }

        // 得到用户
        User user = userService.getUser(userId);
        // 设置更新信息
        String salt = user.getSalt();
        // 密码加密
        String md5Pwd = userService.encryptionPwd(pwdForm.getPwd(),salt);
        if (user.getPwd().equals(md5Pwd)){
            throw new WebsiteException(WebsiteExceptionEnum .PWD_NOT_MODIFY);
        }
        // 设置密码
        user.setPwd(md5Pwd);
        // 更新用户
        userService.updateUser(user);
        // 退出
        userService.logOut(userId);

        return JsonUtil.success();
    }

    /**
     * 登录
     * @param userId 用户id
     * @param perms 权限：0为普通用户，1为内部成员，2为管理员
     * @return
     */
    @RequiresRoles("admin")
    @GetMapping("/authorize")
    public JsonVO<String> authorize(@RequestParam String userId,
                            @RequestParam
                            @Max(value = 2,message = "权限不能大于2")
                            @Min(value = -1,message = "权限不能小于-1") int perms,
                            @RequestHeader("token") String token){

        // 检查用户是否存在
        User user = userService.getUser(userId);

        // 检查用户是否是管理员
        if (userService.isAdmin(user)){
            throw new WebsiteException(WebsiteExceptionEnum.CANNOT_OPERATE_ON_ADMIN);
        }
        if (user.getPerms().equals(perms)){
            throw new WebsiteException(WebsiteExceptionEnum.PERMISSIONS_CANNOT_EQUAL);
        }
        // 更新权限
        user.setPerms(perms);

        userService.updateUser(user);

        return  JsonUtil.success();
    }

    /**
     * 展示所有用户
     * @param page 页数
     * @param num 数量
     * @return
     */
    @RequiresRoles("admin")
    @GetMapping("/showMany")
    public JsonVO<Object> showUsers(@Min(value = 0,message = "页数不能少于0") @RequestParam  int page,
                            @Min(value = 1,message = "数量不能少于1") @RequestParam  int num){

        // 获取用户
        List<User> userList = userService.getUsers(page,num);
        // 设置返回VO
        List<UserVO> userVOList = new ArrayList<>();
        userList.forEach(user -> userVOList.add(userService.getUserVO(user)));

        return JsonUtil.success(userVOList);
    }

    /**
     * 展示用户
     * @param token token
     * @return
     */
    @RequiresRoles("user")
    @GetMapping("/showSelf")
    public JsonVO<Object> showSelf(@RequestHeader("token")String token){

        User user= userService.getUser(JwtUtil.getUserId(token));
        // 设置返回VO
        UserVO userVO = userService.getUserVO(user);
        return JsonUtil.success(userVO);
    }

    /**
     * 展示用户
     * @param id y用户id
     * @return
     */
    @RequiresRoles("admin")
    @GetMapping("/show")
    public JsonVO<Object> show(@Size(min = 11,max = 11,message = "id长度出错") @RequestParam String id){

        User user= userService.getUser(id);
        // 设置返回VO
        UserVO userVO = userService.getUserVO(user);

        return JsonUtil.success(userVO);
    }

    /**
     * 退出
     * @param token token
     * @return
     */
    @RequiresRoles("user")
    @GetMapping("/logOut")
    public JsonVO<String> logOut(@RequestHeader("token")String token){
        // 通过设置最近登陆时间让token失效
        userService.logOut(JwtUtil.getUserId(token));

        return JsonUtil.success();
    }

    /**
     * 展示所有内部用户
     * @param page 页数
     * @param num 数量
     * @return
     */
    @RequiresRoles("insider")
    @GetMapping("/userBook")
    public JsonVO<Object> userBook(@Min(value = 0,message = "页数不能少于0") @RequestParam  int page,
                                    @Min(value = 2,message = "数量不能少于1") @RequestParam  int num){

        // 获取用户
        List<User> userList = userService.getUsers(page,num);
        // 设置返回VO
        List<UserVO> userVOList = new ArrayList<>();
        userList.forEach(user ->{
            if (userService.isInsider(user)){
                userVOList.add(userService.getUserVO(user));
            }
        } );

        return JsonUtil.success(userVOList);
    }

    /**
     * 获得总数
     * @return
     */
    @RequiresRoles("insider")
    @GetMapping("/getNum")
    public JsonVO<Object> getNum( @RequestHeader("token")String token){
        int  num = userService.getNum();


        Map<String,Integer> numMap = new HashMap<>();

        numMap.put("num",num);

        return JsonUtil.success(numMap);
    }


    /**
     * 获得总数
     * @return
     */
    @RequiresRoles("insider")
    @GetMapping("/getSearchNum")
    public JsonVO<Object> getSearchNum(@RequestParam String name, @RequestHeader("token")String token){
        int  num = userService.getNum(name);


        Map<String,Integer> numMap = new HashMap<>();

        numMap.put("num",num);

        return JsonUtil.success(numMap);
    }

    /**
     * 获得总数
     * @return
     */
    @RequiresRoles("insider")
    @GetMapping("/search")
    public JsonVO<Object> search(@RequestParam String name,
                                 @Min(value = 0,message = "页数不能少于0") @RequestParam  int page,
                                 @Min(value = 1,message = "数量不能少于1") @RequestParam  int num,
                                 @RequestHeader("token")String token){
        // 获取用户
        List<User> userByName = userService.getUserByName(name, page, num);

        // 设置返回VO
        List<UserVO> userVOList = new ArrayList<>();

        userByName.forEach(user -> userVOList.add(userService.getUserVO(user)));

        return JsonUtil.success(userVOList);

    }

    @RequiresRoles("user")
    @PostMapping("/uploadAvatar")
    public JsonVO<String> uploadAvatar(@RequestParam MultipartFile file, @RequestHeader("token")String token){

        String userId = JwtUtil.getUserId(token);


        userService.uploadAvatar(file, userId);

        return JsonUtil.success();
    }

    @GetMapping("/getCode/{type}")
    public JsonVO<String> getCode(@RequestParam @Email(message = "必须为正确邮箱格式") String userId,@PathVariable Integer type){
        ToEmail email;
        if(type == 0){
            email = userService.getEmail(userId,"注册账号");
        }else{
            email = userService.getEmail(userId, "修改密码");
        }
        userService.sendEmail(email);

        return JsonUtil.success();
    }
}
